#ifndef PATTERNMATCHER_H_
#define PATTERNMATCHE_H_

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include "../go/Board.h"

using namespace std;

const int MAXN = 13;
const int EMPTY = 0;
const int ENEMY = 1;
const int FRIEND = 2;
const int N = 5000;
const int RNN = 1000;

/*
 const int map[MAXN][MAXN] = {
 0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,1,0,0,0,
 0,0,0,1,0,0,0,0,0,1,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0};
 */

class PatternMatcher {
	int map[MAXN][MAXN];

	char p[N][MAXN][MAXN];
	char pr[MAXN * MAXN];
	int prn;
	int r[N], c[N];
	int n;
	const Board& board;
	
	SgPoint ret[RNN];
	int rn;
public:

	PatternMatcher(const Board& b) :
		board(b) {
		inputData();
	}

	void inputData() {
		ifstream input("patterns.txt");
		string str;
		n = 0;
		//SgDebug() << n << endl;
		while (!input.eof()) {
			getline(input, str, '\n');
			//SgDebug() << str << endl;
			if (str.length() == 0) {
				n++;
				//SgDebug() << n << endl;
				r[n] = 0;
				continue;
			}
			c[n] = str.length();
			for (int i = 0; i < str.length(); i++)
				p[n][r[n]][i] = str[i];
			r[n]++;
		}
		input.close();
		//SgDebug() << n << " patterns.\n";

		for (int k = 0; k < n; k++) {
			for (int i = 0; i < r[k]; i++)
				for (int j = 0; j < c[k]; j++) {
					p[n + k][i][c[k] - j - 1] = p[k][i][j];
					p[n * 2 + k][r[k] - i - 1][j] = p[k][i][j];
					p[n * 3 + k][r[k] - i - 1][c[k] - j - 1] = p[k][i][j];
				}
			r[n * 3 + k] = r[n * 2 + k] = r[n + k] = r[k];
			c[n * 3 + k] = c[n * 2 + k] = c[n + k] = c[k];
		}
		n = n * 4;
	}

	SgPoint* match() {
		rn = 0;
		
		for (int i = 0; i < RNN; i++)
			ret[i] = SG_NULLPOINT;

		for (int i = 0; i < MAXN; i++)
			for (int j = 0; j < MAXN; j++) {
				int c = board.getColor(j + 1, i + 1);
				if (c == SG_EMPTY)
					map[i][j] = EMPTY;
				else if (c == board.toPlay())
					map[i][j] = FRIEND;
				else
					map[i][j] = ENEMY;
			}

		for (int k = 0; k < n; k++) {
			int t, tt;
			bool flag;

			t = 0;
			flag = true;
			for (int i = 0; i < r[k]; i++)
				for (int j = 0; j < c[k]; j++) {
					if (!check(map[i][j], p[k][t / c[k]][t % c[k]]))
						flag = false;
					if (p[k][t / c[k]][t % c[k]] == '*')
						tt = i * MAXN + j;
					t++;
				}

			//SgDebug() << flag << endl;
			//SgDebug() << tt % MAXN + 1 << " " << tt / MAXN + 1 << endl;
			if (flag) {
				//SgDebug() << "AA" << endl;
				//SgDebug() << k << endl;
				if (map[tt / MAXN][tt % MAXN] == EMPTY)
				add(SgPointUtil::Pt(tt % MAXN + 1, tt / MAXN + 1));
			}

			t = 0;
			flag = true;
			for (int i = 0; i < r[k]; i++)
				for (int j = MAXN - 1; j >= MAXN - c[k]; j--) {
					if (!check(map[i][j], p[k][t / c[k]][t % c[k]]))
						flag = false;
					if (p[k][t / c[k]][t % c[k]] == '*')
						tt = i * MAXN + j;
					t++;
				}
			if (flag) {
				//SgDebug() << "AD" << endl;
				if (map[tt / MAXN][tt % MAXN] == EMPTY)
				add(SgPointUtil::Pt(tt % MAXN + 1, tt / MAXN + 1));
			}

			t = 0;
			flag = true;
			for (int i = MAXN - 1; i >= MAXN - r[k]; i--)
				for (int j = 0; j < c[k]; j++) {
					if (!check(map[i][j], p[k][t / c[k]][t % c[k]]))
						flag = false;
					if (p[k][t / c[k]][t % c[k]] == '*')
						tt = i * MAXN + j;
					t++;
				}
			if (flag){
				//SgDebug() << "DA" << endl;
				if (map[tt / MAXN][tt % MAXN] == EMPTY)
				add(SgPointUtil::Pt(tt % MAXN + 1, tt / MAXN + 1));
			}

			t = 0;
			flag = true;
			for (int i = MAXN - 1; i >= MAXN - r[k]; i--)
				for (int j = MAXN - 1; j >= MAXN - c[k]; j--) {
					if (!check(map[i][j], p[k][t / c[k]][t % c[k]]))
						flag = false;
					if (p[k][t / c[k]][t % c[k]] == '*')
						tt = i * MAXN + j;
					t++;
				}
			if (flag) {
				//SgDebug() << "DD" << endl;
				if (map[tt / MAXN][tt % MAXN] == EMPTY)
				add(SgPointUtil::Pt(tt % MAXN + 1, tt / MAXN + 1));
			}
		}
		return ret;
	}

private:
	void add(SgPoint p) {
		ret[rn] = p;
		rn ++;
	}

	bool check(int v, char c) {
		if (v != EMPTY && c == '*')
			return false;
		if (v == EMPTY && c != 'X' && c != 'O')
			return true;
		if (v == ENEMY && (c == 'X' || c == 'x' || c == '?'))
			return true;
		if (v == FRIEND && (c == 'O' || c == 'o' || c == '?'))
			return true;
		return false;
	}

	void printp(int k) {
		for (int i = 0; i < r[k]; i++) {
			for (int j = 0; j < c[k]; j++)
				cout << p[k][i][j];
			cout << endl;
		}
	}

};

#endif
